package com.myth.mysql2dm.filters;

import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.FilterEventAdapter;
import com.alibaba.druid.proxy.jdbc.*;
import com.myth.mysql2dm.utils.DmUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;

/**
 * @author Myth
 * @date 2023/8/8 17:25
 * 参考
 * @see com.alibaba.druid.filter.encoding.EncodingConvertFilter
 */
public class DmDruidFilter extends FilterEventAdapter {

    private final static Logger LOGGER = LoggerFactory.getLogger(DmDruidFilter.class);

    // //////////////// Connection

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
            throws SQLException {
        return super.connection_prepareStatement(chain, connection, modifySqlForDm(chain, sql));
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, int autoGeneratedKeys) throws SQLException {
        return super.connection_prepareStatement(chain, connection, modifySqlForDm(chain, sql), autoGeneratedKeys);
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, int resultSetType, int resultSetConcurrency)
            throws SQLException {
        return super.connection_prepareStatement(chain, connection, modifySqlForDm(chain, sql), resultSetType,
                resultSetConcurrency);
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, int resultSetType, int resultSetConcurrency,
                                                              int resultSetHoldability) throws SQLException {
        return super.connection_prepareStatement(chain, connection, modifySqlForDm(chain, sql), resultSetType,
                resultSetConcurrency, resultSetHoldability);
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, int[] columnIndexes) throws SQLException {
        return super.connection_prepareStatement(chain, connection, modifySqlForDm(chain, sql), columnIndexes);
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, String[] columnNames) throws SQLException {
        return super.connection_prepareStatement(chain, connection, modifySqlForDm(chain, sql), columnNames);
    }

    // / precall

    @Override
    public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql)
            throws SQLException {
        return super.connection_prepareCall(chain, connection, modifySqlForDm(chain, sql));
    }

    @Override
    public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
                                                         int resultSetType, int resultSetConcurrency)
            throws SQLException {
        return super.connection_prepareCall(chain, connection, modifySqlForDm(chain, sql), resultSetType,
                resultSetConcurrency);
    }

    @Override
    public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
                                                         int resultSetType, int resultSetConcurrency,
                                                         int resultSetHoldability) throws SQLException {
        return super.connection_prepareCall(chain, connection, modifySqlForDm(chain, sql), resultSetType,
                resultSetConcurrency, resultSetHoldability);
    }

    // nativeSQL

    @Override
    public String connection_nativeSQL(FilterChain chain, ConnectionProxy connection, String sql) throws SQLException {
        String encodedSql = modifySqlForDm(chain, sql);
        return super.connection_nativeSQL(chain, connection, encodedSql);
    }

    // ////////////// statement

    @Override
    public void statement_addBatch(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
        super.statement_addBatch(chain, statement, modifySqlForDm(chain, sql));
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
        return super.statement_execute(chain, statement, modifySqlForDm(chain, sql));
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
            throws SQLException {
        return super.statement_execute(chain, statement, modifySqlForDm(chain, sql), autoGeneratedKeys);
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
            throws SQLException {
        return super.statement_execute(chain, statement, modifySqlForDm(chain, sql), columnIndexes);
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
            throws SQLException {
        return super.statement_execute(chain, statement, modifySqlForDm(chain, sql), columnNames);
    }

    @Override
    public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
            throws SQLException {
        return super.statement_executeQuery(chain, statement, modifySqlForDm(chain, sql));
    }

    @Override
    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
        return super.statement_executeUpdate(chain, statement, modifySqlForDm(chain, sql));
    }

    @Override
    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
            throws SQLException {
        return super.statement_executeUpdate(chain, statement, modifySqlForDm(chain, sql),
                autoGeneratedKeys);
    }

    @Override
    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
            throws SQLException {
        return super.statement_executeUpdate(chain, statement, modifySqlForDm(chain, sql),
                columnIndexes);
    }

    @Override
    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
            throws SQLException {
        return super.statement_executeUpdate(chain, statement, modifySqlForDm(chain, sql), columnNames);
    }

    private String modifySqlForDm(FilterChain chain, String sql) {
        if (isDm(chain)) {
            return DmUtils.modifySql(sql);
        }
        return sql;
    }

    private boolean isDm(FilterChain chain) {
        String dbType = chain.getDataSource().getDbType();
        return StrUtil.equals(dbType, "dm");
    }
}
